
namespace CloudNinja.Metering.Common.Configuration
{
    using System;
    using System.Configuration;
    using System.Linq;

    public class ProvidersCollection : ConfigurationElementCollection
    {
        public override ConfigurationElementCollectionType CollectionType
        {
            get
            {
                return ConfigurationElementCollectionType.BasicMap;
            }
        }

        public ProviderElement this[int index]
        {
            get
            {
                return (ProviderElement)this.BaseGet(index);
            }

            set
            {
                if (this.BaseGet(index) != null)
                {
                    this.BaseRemoveAt(index);
                }

                this.BaseAdd(index, value);
            }
        }

        public void Add(ProviderElement element)
        {
            this.BaseAdd(element);
        }

        public void Clear()
        {
            this.BaseClear();
        }

        public void Remove(ProviderElement element)
        {
            this.BaseRemove(element.Type);
        }

        public void Remove(string name)
        {
            this.BaseRemove(name);
        }

        public void RemoveAt(int index)
        {
            this.BaseRemoveAt(index);
        }

        protected override string ElementName
        {
            get
            {
                return "Provider";
            }
        }

        protected override bool OnDeserializeUnrecognizedElement(string elementName, System.Xml.XmlReader reader)
        {
            var type = reader.GetAttribute("Type");
            return base.OnDeserializeUnrecognizedElement(type, reader);
        }

        protected override ConfigurationElement CreateNewElement()
        {
            return this.CreateNewElement(string.Empty);
        }

        protected override object GetElementKey(ConfigurationElement element)
        {
            return ((ProviderElement)element).Type;
        }


        protected override ConfigurationElement CreateNewElement(string elementType)
        {
            try
            {
                var providerType = Type.GetType(elementType);

                if (providerType == null)
                {
                    throw new ConfigurationErrorsException(string.Format("Cannot find type {0}", elementType));
                }

                var configurationElementTypeAttribute =
                    providerType.GetCustomAttributes(typeof(ProviderConfigElementTypeAttribute), false).FirstOrDefault() as ProviderConfigElementTypeAttribute;

                if (configurationElementTypeAttribute == null)
                {
                    throw new ConfigurationErrorsException(string.Format("Please make sure to specify the configuration element type in the provider's ProviderConfigElementType custom class attribute for {0}", elementType));
                }

                var configurationElementType = configurationElementTypeAttribute.ConfigurationType;

                return (ConfigurationElement)Activator.CreateInstance(configurationElementType);
            }
            catch (Exception exception)
            {
                throw new ConfigurationErrorsException(string.Format("Cannot create type {0}", elementType), exception);
            }
        }

        protected override bool IsElementName(string elementName)
        {
            var typ = Type.GetType(elementName);
            return typ != null;
        }

        protected override bool OnDeserializeUnrecognizedAttribute(string name, string value)
        {
            return name.Equals("Name") || name.Equals("CollectInterval") || name.Equals("Type") || base.OnDeserializeUnrecognizedAttribute(name, value);
        }
    }
}